package org.hfy.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.hfy.dto.OptionDTO;
import org.hfy.dto.QuotationQueryDTO;
import org.hfy.entity.Quotation;
import org.hfy.entity.QuotationCalculation;
import org.hfy.entity.QuotationCost;
import org.hfy.entity.QuotationItem;
import org.hfy.enums.QuotationStatus;
import org.hfy.mapper.CustomerMapper;
import org.hfy.mapper.EmployeeMapper;
import org.hfy.mapper.QuotationCalculationMapper;
import org.hfy.mapper.QuotationCostMapper;
import org.hfy.mapper.QuotationItemMapper;
import org.hfy.mapper.QuotationMapper;
import org.hfy.service.ContractService;
import org.hfy.service.QuotationService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 报价单服务实现类
 * 
 * @author hfy
 * @version 1.0
 */
@Slf4j
@Service
public class QuotationServiceImpl extends ServiceImpl<QuotationMapper, Quotation> implements QuotationService {

    private final QuotationItemMapper quotationItemMapper;
    private final QuotationCalculationMapper quotationCalculationMapper;
    private final QuotationCostMapper quotationCostMapper;
    private final ContractService contractService;
    private final CustomerMapper customerMapper;
    private final EmployeeMapper employeeMapper;

    public QuotationServiceImpl(QuotationItemMapper quotationItemMapper,
                               QuotationCalculationMapper quotationCalculationMapper,
                               QuotationCostMapper quotationCostMapper,
                               @Lazy ContractService contractService,
                               CustomerMapper customerMapper,
                               EmployeeMapper employeeMapper) {
        this.quotationItemMapper = quotationItemMapper;
        this.quotationCalculationMapper = quotationCalculationMapper;
        this.quotationCostMapper = quotationCostMapper;
        this.contractService = contractService;
        this.customerMapper = customerMapper;
        this.employeeMapper = employeeMapper;
    }

    @Override
    public IPage<Quotation> getQuotationPage(QuotationQueryDTO query) {
        Page<Quotation> page = new Page<>(query.getCurrent(), query.getSize());
        return baseMapper.selectQuotationPage(page, query);
    }

    @Override
    public Quotation getQuotationWithItemsById(Long id) {
        return baseMapper.selectQuotationWithItemsById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Quotation createQuotation(Quotation quotation) {
        // 生成报价单号
        if (!StringUtils.hasText(quotation.getQuotationNo())) {
            quotation.setQuotationNo(generateQuotationNo());
        }
        
        // 设置默认状态
        if (!StringUtils.hasText(quotation.getStatus())) {
            quotation.setStatus(QuotationStatus.DRAFT.getCode());
        }
        
        // 计算总金额
        calculateTotalAmount(quotation);
        
        // 保存报价单主表
        save(quotation);
        
        // 保存明细信息
        saveQuotationItems(quotation);
        
        return quotation;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Quotation updateQuotation(Long id, Quotation quotation) {
        quotation.setId(id);
        
        // 计算总金额
        calculateTotalAmount(quotation);
        
        // 更新主表
        updateById(quotation);
        
        // 更新明细信息
        updateQuotationItems(quotation);
        
        return quotation;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteQuotation(Long id) {
        // 删除明细数据
        quotationItemMapper.deleteByQuotationId(id);
        quotationCalculationMapper.deleteByQuotationId(id);
        quotationCostMapper.deleteByQuotationId(id);
        
        // 删除主表数据
        return removeById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long generateContract(Long quotationId) {
        // 检查报价单状态
        Quotation quotation = getById(quotationId);
        if (quotation == null) {
            throw new RuntimeException("报价单不存在");
        }
        
        QuotationStatus currentStatus = QuotationStatus.fromCode(quotation.getStatus());
        if (!currentStatus.canGenerateContract()) {
            throw new RuntimeException("当前状态不允许生成合同，只有已提交或已生成合同的报价单才能生成合同");
        }
        
        // 更新报价单状态为已生成合同
        quotation.setStatus(QuotationStatus.CONTRACT_GENERATED.getCode());
        updateById(quotation);
        
        // 调用合同服务生成合同
        return contractService.generateContractByQuotationId(quotationId);
    }

    @Override
    public List<OptionDTO> getCustomerOptions() {
        try {
            return customerMapper.selectCustomerOptions();
        } catch (Exception e) {
            log.error("获取客户选项列表失败", e);
            return Collections.emptyList();
        }
    }

    @Override
    public List<OptionDTO> getEmployeeOptions() {
        try {
            return employeeMapper.selectEmployeeOptions();
        } catch (Exception e) {
            log.error("获取员工选项列表失败", e);
            return Collections.emptyList();
        }
    }

    @Override
    public String generateQuotationNo() {
        String dateStr = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String prefix = "BJ" + dateStr;
        
        // 查询当天已有的报价单数量，生成序号
        try {
            // 构建查询条件：今天创建的报价单
            LocalDate today = LocalDate.now();
            String likePattern = prefix + "%";
            
            // 查询当天以该前缀开头的报价单数量
            long count = baseMapper.selectCount(
                new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<Quotation>()
                    .like("quotation_no", likePattern)
                    .eq("deleted", 0)
            );
            
            // 序号从1开始，格式化为4位数字
            int sequence = (int) (count + 1);
            return prefix + String.format("%04d", sequence);
            
        } catch (Exception e) {
            log.error("生成报价单号失败，使用默认序号", e);
            // 如果查询失败，使用时间戳后4位作为序号
            int sequence = (int) (System.currentTimeMillis() % 10000);
            return prefix + String.format("%04d", sequence);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean submitQuotation(Long id) {
        Quotation quotation = getById(id);
        if (quotation == null) {
            throw new RuntimeException("报价单不存在");
        }
        
        quotation.setStatus(QuotationStatus.SUBMITTED.getCode());
        return updateById(quotation);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Quotation saveDraft(Quotation quotation) {
        quotation.setStatus(QuotationStatus.DRAFT.getCode());
        
        if (quotation.getId() == null) {
            return createQuotation(quotation);
        } else {
            return updateQuotation(quotation.getId(), quotation);
        }
    }

    /**
     * 计算总金额
     */
    private void calculateTotalAmount(Quotation quotation) {
        if (quotation.getItems() == null || quotation.getItems().isEmpty()) {
            quotation.setTotalAmount(BigDecimal.ZERO);
            quotation.setTotalTaxAmount(BigDecimal.ZERO);
            return;
        }
        
        BigDecimal totalAmount = quotation.getItems().stream()
            .map(QuotationItem::getTotalAmount)
            .filter(amount -> amount != null)
            .reduce(BigDecimal.ZERO, BigDecimal::add);
            
        quotation.setTotalAmount(totalAmount);
        
        // 如果含税，计算含税总金额（13%税率）
        if (Boolean.TRUE.equals(quotation.getIsTaxIncluded())) {
            quotation.setTotalTaxAmount(totalAmount.multiply(new BigDecimal("1.13")));
        } else {
            quotation.setTotalTaxAmount(totalAmount);
        }
    }

    /**
     * 保存报价单明细
     */
    private void saveQuotationItems(Quotation quotation) {
        if (quotation.getItems() == null || quotation.getItems().isEmpty()) {
            return;
        }
        
        // 准备要保存的明细列表
        List<QuotationItem> itemsToSave = new ArrayList<>();
        List<QuotationCalculation> calculationsToSave = new ArrayList<>();
        List<QuotationCost> costsToSave = new ArrayList<>();
        
        for (int i = 0; i < quotation.getItems().size(); i++) {
            QuotationItem item = quotation.getItems().get(i);
            
            // 清空 id，让数据库自动生成
            item.setId(null);
            item.setQuotationId(quotation.getId());
            item.setItemNo(i + 1);
            itemsToSave.add(item);
            
            // 保存计算信息
            if (item.getCalculation() != null) {
                item.getCalculation().setId(null);
                item.getCalculation().setQuotationId(quotation.getId());
                item.getCalculation().setItemNo(i + 1);
                calculationsToSave.add(item.getCalculation());
            }
            
            // 保存成本信息
            if (item.getCosts() != null) {
                item.getCosts().setId(null);
                item.getCosts().setQuotationId(quotation.getId());
                item.getCosts().setItemNo(i + 1);
                costsToSave.add(item.getCosts());
            }
        }
        
        // 批量插入明细
        if (!itemsToSave.isEmpty()) {
            quotationItemMapper.insertBatch(itemsToSave);
        }
        
        // 批量插入计算信息
        if (!calculationsToSave.isEmpty()) {
            quotationCalculationMapper.insertBatch(calculationsToSave);
        }
        
        // 批量插入成本信息
        if (!costsToSave.isEmpty()) {
            quotationCostMapper.insertBatch(costsToSave);
        }
    }

    /**
     * 更新报价单明细
     */
    private void updateQuotationItems(Quotation quotation) {
        // 删除旧的明细数据
        quotationItemMapper.deleteByQuotationId(quotation.getId());
        quotationCalculationMapper.deleteByQuotationId(quotation.getId());
        quotationCostMapper.deleteByQuotationId(quotation.getId());
        
        // 重新保存明细数据
        saveQuotationItems(quotation);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStatusToContractApproved(Long quotationId) {
        Quotation quotation = getById(quotationId);
        if (quotation == null) {
            throw new RuntimeException("报价单不存在");
        }
        
        QuotationStatus currentStatus = QuotationStatus.fromCode(quotation.getStatus());
        if (currentStatus != QuotationStatus.CONTRACT_GENERATED) {
            throw new RuntimeException("当前状态不允许审核通过，只有已生成合同的报价单才能审核");
        }
        
        quotation.setStatus(QuotationStatus.CONTRACT_APPROVED.getCode());
        return updateById(quotation);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStatusToContractRejected(Long quotationId) {
        Quotation quotation = getById(quotationId);
        if (quotation == null) {
            throw new RuntimeException("报价单不存在");
        }
        
        QuotationStatus currentStatus = QuotationStatus.fromCode(quotation.getStatus());
        if (currentStatus != QuotationStatus.CONTRACT_GENERATED) {
            throw new RuntimeException("当前状态不允许审核拒绝，只有已生成合同的报价单才能审核");
        }
        
        quotation.setStatus(QuotationStatus.CONTRACT_REJECTED.getCode());
        return updateById(quotation);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStatusToOutsourcing(Long quotationId) {
        Quotation quotation = getById(quotationId);
        if (quotation == null) {
            throw new RuntimeException("报价单不存在");
        }
        
        QuotationStatus currentStatus = QuotationStatus.fromCode(quotation.getStatus());
        if (!currentStatus.canOutsource()) {
            throw new RuntimeException("当前状态不允许外发加工，只有合同审核通过、外发加工中或已入库的报价单才能外发加工");
        }
        
        // 只有合同审核通过状态才需要更新为外发加工中，其他状态保持不变
        if (currentStatus == QuotationStatus.CONTRACT_APPROVED) {
            quotation.setStatus(QuotationStatus.OUTSOURCING.getCode());
            return updateById(quotation);
        }
        
        return true; // 已经是外发加工中或已入库状态，返回成功
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStatusToWarehoused(Long quotationId) {
        Quotation quotation = getById(quotationId);
        if (quotation == null) {
            throw new RuntimeException("报价单不存在");
        }
        
        QuotationStatus currentStatus = QuotationStatus.fromCode(quotation.getStatus());
        if (!currentStatus.canWarehouse()) {
            throw new RuntimeException("当前状态不允许入库，只有外发加工中的报价单才能入库");
        }
        
        quotation.setStatus(QuotationStatus.WAREHOUSED.getCode());
        return updateById(quotation);
    }

    @Override
    public List<Quotation> getQuotationsByStatus(List<String> statusList) {
        if (statusList == null || statusList.isEmpty()) {
            return new ArrayList<>();
        }
        
        LambdaQueryWrapper<Quotation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Quotation::getStatus, statusList)
                   .eq(Quotation::getDeleted, 0)
                   .orderByDesc(Quotation::getCreatedAt);
        
        return list(queryWrapper);
    }
} 